package handler

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"time"

	"project-info/src/model"
	"github.com/golang-jwt/jwt/v4"

	"project-info/src/lib")

// UserInfo 用户信息端点
// GET/POST /oidc/userinfo
func UserInfo(c *lib.GinContext) (err error) {
	// 从Authorization头获取访问令牌
	accessToken := extractBearerToken(c)
	if accessToken == "" {
		return c.JSON(http.StatusUnauthorized, map[string]interface{}{
			"error":             "invalid_token",
			"error_description": "Missing or invalid access token",
		})
	}

	// 验证访问令牌
	db := model.DB()
	var oidcAccessToken model.OIDCAccessToken
	if err := db.Where("token = ? AND deleted = 0 AND revoked = 0", accessToken).First(&oidcAccessToken).Error; err != nil {
		return c.JSON(http.StatusUnauthorized, map[string]interface{}{
			"error":             "invalid_token",
			"error_description": "Invalid access token",
		})
	}

	// 检查令牌是否过期
	if !oidcAccessToken.ExpiresAt.IsZero() && time.Now().After(oidcAccessToken.ExpiresAt) {
		return c.JSON(http.StatusUnauthorized, map[string]interface{}{
			"error":             "invalid_token",
			"error_description": "Access token expired",
		})
	}

	// 检查scope是否包含openid
	if !strings.Contains(oidcAccessToken.Scope, "openid") {
		return c.JSON(http.StatusForbidden, map[string]interface{}{
			"error":             "insufficient_scope",
			"error_description": "The request requires higher privileges than provided by the access token",
		})
	}

	// 获取用户信息
	userInfo := getUserInfo(oidcAccessToken.UserID, oidcAccessToken.Scope)

	return c.JSON(http.StatusOK, userInfo)
}

// extractBearerToken 从请求中提取Bearer令牌
func extractBearerToken(c *lib.GinContext) string {
	// 首先检查Authorization头
	authHeader := c.Request().Header.Get("Authorization")
	if authHeader != "" {
		parts := strings.SplitN(authHeader, " ", 2)
		if len(parts) == 2 && strings.ToLower(parts[0]) == "bearer" {
			return parts[1]
		}
	}

	// 如果是POST请求，也检查表单参数
	if c.Request().Method == "POST" {
		return c.PostForm("access_token")
	}

	// 检查查询参数
	return c.QueryParam("access_token")
}

// getUserInfo 根据用户ID和scope获取用户信息
func getUserInfo(userID uint64, scope string) map[string]interface{} {
	userInfo := map[string]interface{}{
		"sub": userID, // subject - 用户唯一标识符
	}

	var user model.User
	err := model.DB().Where("id = ? and deleted = 0", userID).First(&user).Error
	if err != nil {
		return userInfo
	}

	// 根据scope添加相应的用户信息
	scopes := strings.Fields(scope)
	scopeConfigs, _ := oidcService.GetScopes(scopes)
	// 2. 动态构建声明
	for _, scopeConfig := range scopeConfigs {
		for _, claim := range scopeConfig.Claims {
			value := getClaimValue(user, claim)
			if value != nil {
				userInfo[claim] = value
			}
		}
	}
	return userInfo
}

func getClaimValue(user model.User, claimName string) interface{} {
	userMeta := map[string]interface{}{}
	json.Unmarshal([]byte(user.Meta), &userMeta)
	// 根据声明名称动态获取值
	switch claimName {
	case "sub":
		return strconv.FormatUint(user.Id, 10)
	case "name", "preferred_username":
		return user.Username
	case "real_name":
		return userMeta["real_name"]
	case "description":
		return user.Describe
	case "roles":
		return getUserRoles(user.Id)
	case "email":
		return userMeta["email"]
	case "email_verified":
		return true
	case "permissions":
		return getUserPermissions(user)
	case "groups":
		return getUserGroups(user)
	}
	return nil
}

// getUserPermissions 获取用户权限
func getUserPermissions(user model.User) []string {
	// 使用menu 中btn 类型的权限code 作为权限
	permissions := []string{}
	model.DB().Model(&model.Menu{}).Where("type = ? and  id in (select menu_id from menu_roles where role_id in (select role_id from role_users where user_id = ?))", "btn", user.Id).Pluck("btn_power", &permissions)
	return permissions
}

// getUserGroups 获取用户组
func getUserGroups(user model.User) []string {
	// TODO 从用户元数据中获取组(暂未实现)
	groups := []string{}
	return groups
}

// TokenIntrospection 令牌内省端点
// POST /oidc/introspect
func TokenIntrospection(c *lib.GinContext) (err error) {
	// 获取要内省的令牌
	token := c.PostForm("token")
	if token == "" {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{
			"error":             "invalid_request",
			"error_description": "Missing token parameter",
		})
	}

	// 获取令牌类型提示
	_ = c.PostForm("token_type_hint")

	// 客户端认证（简化实现）
	clientID := c.PostForm("client_id")
	clientSecret := c.PostForm("client_secret")
	if clientID != "" {
		db := model.DB()
		var oidcClient model.OIDCClient
		if err := db.Where("client_id = ? AND deleted = 0", clientID).First(&oidcClient).Error; err != nil || oidcClient.ClientSecret != clientSecret {
			return c.JSON(http.StatusUnauthorized, map[string]interface{}{
				"error":             "invalid_client",
				"error_description": "Invalid client credentials",
			})
		}
	}

	// 检查令牌是否为访问令牌
	db := model.DB()
	var accessToken model.OIDCAccessToken
	if err := db.Where("token = ? AND deleted = 0 AND revoked = 0", token).First(&accessToken).Error; err == nil {
		// 检查令牌是否过期
		active := accessToken.ExpiresAt.IsZero() || time.Now().Before(accessToken.ExpiresAt)

		response := map[string]interface{}{
			"active": active,
		}

		if active {
			response["client_id"] = accessToken.ClientID
			response["username"] = getUsernameByID(fmt.Sprintf("%d", accessToken.UserID))
			response["scope"] = accessToken.Scope
			response["sub"] = accessToken.UserID
			response["aud"] = accessToken.ClientID
			response["iss"] = "http://localhost:9999"
			if !accessToken.ExpiresAt.IsZero() {
				response["exp"] = accessToken.ExpiresAt.Unix()
			}
			if accessToken.CreateTime != nil {
				response["iat"] = accessToken.CreateTime.Unix()
			}
			response["token_type"] = "Bearer"
		}

		return c.JSON(http.StatusOK, response)
	}

	// 检查令牌是否为刷新令牌
	var refreshToken model.OIDCRefreshToken
	if err := db.Where("token = ? AND deleted = 0 AND revoked = 0", token).First(&refreshToken).Error; err == nil {
		// 检查令牌是否过期
		active := refreshToken.ExpiresAt.IsZero() || time.Now().Before(refreshToken.ExpiresAt)

		response := map[string]interface{}{
			"active": active,
		}

		if active {
			response["client_id"] = refreshToken.ClientID
			response["username"] = getUsernameByID(fmt.Sprintf("%d", refreshToken.UserID))
			response["scope"] = refreshToken.Scope
			response["sub"] = refreshToken.UserID
			response["aud"] = refreshToken.ClientID
			response["iss"] = "http://localhost:9999"
			if !refreshToken.ExpiresAt.IsZero() {
				response["exp"] = refreshToken.ExpiresAt.Unix()
			}
			response["token_type"] = "refresh_token"
		}

		return c.JSON(http.StatusOK, response)
	}

	// 尝试解析JWT令牌（ID令牌）
	if strings.HasPrefix(token, "eyJ") { // JWT令牌通常以eyJ开头
		if claims, err := parseJWTToken(token); err == nil {
			// 检查令牌是否过期
			exp, ok := claims["exp"].(float64)
			active := ok && time.Now().Unix() < int64(exp)

			response := map[string]interface{}{
				"active": active,
			}

			if active {
				response["client_id"] = claims["aud"]
				response["username"] = claims["name"]
				response["sub"] = claims["sub"]
				response["aud"] = claims["aud"]
				response["iss"] = claims["iss"]
				response["exp"] = int64(exp)
				response["iat"] = claims["iat"]
				response["token_type"] = "id_token"
			}

			return c.JSON(http.StatusOK, response)
		}
	}

	// 令牌无效或不存在
	return c.JSON(http.StatusOK, map[string]interface{}{
		"active": false,
	})
}

// parseJWTToken 解析JWT令牌
func parseJWTToken(tokenString string) (jwt.MapClaims, error) {
	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		// 验证签名方法
		if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
			return nil, jwt.NewValidationError("unexpected signing method", jwt.ValidationErrorSignatureInvalid)
		}
		return rsaPublicKey, nil
	})

	if err != nil {
		return nil, err
	}

	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		return claims, nil
	}

	return nil, jwt.NewValidationError("invalid token", jwt.ValidationErrorClaimsInvalid)
}

// getUsernameByID 根据用户ID获取用户名
func getUsernameByID(userID string) string {
	id, err := strconv.ParseUint(userID, 10, 64)
	if err != nil {
		return "unknown"
	}

	var user model.User
	err = model.DB().Where("id = ? and deleted = 0", id).First(&user).Error
	if err != nil {
		return "unknown"
	}

	return user.Username
}

// getUserRoles 根据用户ID获取用户角色
func getUserRoles(userID uint64) []map[string]interface{} {
	var roles []map[string]interface{}

	// 查询用户角色关联表
	var roleUsers []model.RoleUser
	err := model.DB().Where("user_id = ?", userID).Find(&roleUsers).Error
	if err != nil {
		return roles
	}

	// 获取角色ID列表
	var roleIDs []uint64
	for _, ru := range roleUsers {
		roleIDs = append(roleIDs, ru.RoleId)
	}

	if len(roleIDs) == 0 {
		return roles
	}

	// 查询角色信息
	var roleList []model.Role
	err = model.DB().Where("id IN (?) AND deleted = 0", roleIDs).Find(&roleList).Error
	if err != nil {
		return roles
	}

	// 提取角色名称
	for _, role := range roleList {
		roles = append(roles, map[string]interface{}{
			"role_id":   role.Id,
			"role_name": role.RoleName,
		})
	}

	return roles
}
